/*
 * @Author: 0x9DEFA478
 * @Date: 2024-09-11 11:29:44
 * @LastEditTime: 2025-10-18 00:19:35
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 * 
 */
#include "SystemProcessWindows.hpp"
#ifdef _WIN32
#include <windows.h>
#include <stdexcept>
#include <fileapi.h>
#include <sstream>
#include <list>
#include "H_Concurrency.hpp"
#include "SystemAPI/Windows/Encoding.hpp"
#include "SystemAPI/Windows/Error.hpp"




static std::string ArgAutoAddEscape(const std::string& Arg){
  std::stringstream ss;
  bool IsExistSpace=false;

  if(Arg.length()<1){
    return "\\\"\\\"";
  }

  for(auto Item:Arg){
    if(Item=='\"'){
      ss<<'\\';
    }else if(Item==' '){
      IsExistSpace=true;
    }
    ss<<Item;
  }

  if(IsExistSpace){
    return '\"'+ss.str()+'\"';
  }

  return ss.str();
}



namespace{

  class Windows_Pipe{

    public:
      Windows_Pipe(DWORD nSize=0);
      ~Windows_Pipe();

      HANDLE Pipe_Read()const{return pipe_Read;}
      HANDLE Pipe_Write()const{return pipe_Write;}

      void CloseRead();
      void CloseWrite();

    private:
      HANDLE pipe_Read;
      HANDLE pipe_Write;
  };

  Windows_Pipe::Windows_Pipe(DWORD nSize){
    SECURITY_ATTRIBUTES sa;
  
    sa.nLength=sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle=TRUE;
    sa.lpSecurityDescriptor=nullptr;
    if(!CreatePipe(&pipe_Read,&pipe_Write,&sa,nSize)){
      throw std::runtime_error("Windows匿名管道创建失败: "+SystemAPI::Windows::GetErrorString());
    }
  }

  Windows_Pipe::~Windows_Pipe(){
    CloseRead();
    CloseWrite();
  }

  void Windows_Pipe::CloseRead(){
    if(pipe_Read==nullptr){
      return;
    }
    CloseHandle(pipe_Read);
    pipe_Read=nullptr;
  }
  void Windows_Pipe::CloseWrite(){
    if(pipe_Write==nullptr){
      return;
    }
    CloseHandle(pipe_Write);
    pipe_Write=nullptr;
  }


  struct SystemProcessWindows_Instance{
    Windows_Pipe Output;
    Windows_Pipe Input;
    PROCESS_INFORMATION proc_info;
    bool pipeIO;
    bool outputIsStop;
    bool inputIsStop;
    bool isStop;
    int Result;

    H::Pointer<char>::Const Cache;

    SystemProcessWindows_Instance(LPSTR cmdstr,bool pipeIO);
    ~SystemProcessWindows_Instance();
    
    H::Pointer<char> Read();
    bool Write(const void* Buffer,int Length);
    bool IsStop();
    void WaitStop();
    void Stop();
  };

  SystemProcessWindows_Instance::SystemProcessWindows_Instance(LPSTR cmdstr,bool pipeIO):Output(0),Input(0),proc_info{0},pipeIO(pipeIO),outputIsStop(false),inputIsStop(false),isStop(false),Result(-1){
    STARTUPINFOA StartupInfo={0};

    if(!SetHandleInformation(Output.Pipe_Read(),HANDLE_FLAG_INHERIT,0)){
      throw std::runtime_error("Windows输出管道设置继承属性失败: "+SystemAPI::Windows::GetErrorString());
    }

    if(!SetHandleInformation(Input.Pipe_Write(),HANDLE_FLAG_INHERIT,0)){
      throw std::runtime_error("Windows输入管道设置继承属性失败: "+SystemAPI::Windows::GetErrorString());
    }
    
    StartupInfo.cb=sizeof(STARTUPINFOA);
    if(pipeIO){
      StartupInfo.hStdError=Output.Pipe_Write();
      StartupInfo.hStdOutput=Output.Pipe_Write();
      StartupInfo.hStdInput=Input.Pipe_Read();
      StartupInfo.dwFlags=STARTF_USESTDHANDLES;
    }

    if(!CreateProcessA(nullptr,cmdstr,nullptr,nullptr,TRUE,0,nullptr,nullptr,&StartupInfo,&proc_info)){
      throw std::runtime_error("Windows进程创建失败 目标命令: "+ SystemAPI::Windows::TextEncodeConvert(cmdstr,CP_ACP,CP_UTF8) +" 错误: "+SystemAPI::Windows::GetErrorString());
    }

    Output.CloseWrite();
    Input.CloseRead();
  }

  SystemProcessWindows_Instance::~SystemProcessWindows_Instance(){
    if(!IsStop()){
      TerminateProcess(proc_info.hProcess,0);
    }

    CloseHandle(proc_info.hProcess);
    CloseHandle(proc_info.hThread);
  }

  H::Pointer<char> SystemProcessWindows_Instance::Read(){
    DWORD readLength;

    if(outputIsStop||(!pipeIO)){
      return H::Pointer<char>();
    }

    auto buffer=H::Pointer<char>::Array(1024);
    auto res=ReadFile(Output.Pipe_Read(),buffer.GetPointer(),buffer.Length(),&readLength,nullptr);
    if((!res)&&(readLength==0)){
      outputIsStop=true;
      return H::Pointer<char>();
    }

    return buffer.Clone(readLength);
  }

  bool SystemProcessWindows_Instance::Write(const void* Buffer,int Length){
    DWORD writeLength;

    if(inputIsStop||(!pipeIO)){
      return false;
    }

    auto res=WriteFile(Input.Pipe_Write(),Buffer,Length,&writeLength,nullptr);
    if(!res){
      inputIsStop=true;
      return false;
    }

    return true;
  }

  bool SystemProcessWindows_Instance::IsStop(){
    if(isStop){
      return true;
    }

    if(WAIT_OBJECT_0==WaitForSingleObject(proc_info.hProcess,0)){
      DWORD ExitCode;
      isStop=true;
      GetExitCodeProcess(proc_info.hProcess,&ExitCode);
      Result=ExitCode;
      return true;
    }

    return false;
  }

  void SystemProcessWindows_Instance::WaitStop(){
    DWORD ExitCode;
    if(isStop){
      return;
    }
    WaitForSingleObject(proc_info.hProcess,INFINITE);
    isStop=true;
    GetExitCodeProcess(proc_info.hProcess,&ExitCode);
    Result=ExitCode;
  }

  void SystemProcessWindows_Instance::Stop(){
    if(isStop){
      return;
    }
    TerminateProcess(proc_info.hProcess,STATUS_TIMEOUT);
    isStop=true;
    Result=STATUS_TIMEOUT;
  }

}



SystemProcessWindows::SystemProcessWindows():Instance(nullptr){}

SystemProcessWindows::~SystemProcessWindows(){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return;
  }

  delete Instance;
}

void SystemProcessWindows::Run(const H::Pointer<std::string>::Const& Command,bool pipeIO){
  SystemProcessWindows_Instance* Instance;
  H::Pointer<char> arg;

  if(this->Instance!=nullptr){
    throw std::runtime_error("SystemProcessWindows对象不能重复Run");
  }

  {
    std::stringstream ss;

    for(H::usize i=0,length=Command.Length();i<length;i++){
      if(i>0){
        ss<<" ";
      }
      ss<<SystemAPI::Windows::TextEncodeConvert(ArgAutoAddEscape(Command[i]),CP_UTF8,CP_ACP);
    }
    
    auto argstr=ss.str();

    arg=arg.Array(argstr.length()+1);
    for(std::size_t i=0,length=argstr.length();i<length;i++){
      arg[i]=argstr[i];
    }
    arg[argstr.length()]='\0';
  }

  Instance=new SystemProcessWindows_Instance(arg.GetPointer(),pipeIO);
  this->Instance=static_cast<void*>(Instance);
}

bool SystemProcessWindows::WriteInput(const std::string& str){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return false;
  }

  return Instance->Write(str.c_str(),str.length());
}

H::Pointer<char> SystemProcessWindows::ReadOutput(){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return H::Pointer<char>();
  }

  if(Instance->Cache){
    auto r=Instance->Cache.Clone();
    Instance->Cache.Set_nullptr();
    return r;
  }

  return Instance->Read();
}

std::string SystemProcessWindows::ReadLine(char SplitChar){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return "";
  }

  for(;;){
    auto& s=Instance->Cache;
    auto len=s.Length();
    for(H::usize SplitIndex=0;SplitIndex<len;SplitIndex++){
      if(s[SplitIndex]==SplitChar){
        std::string r=std::string(s.GetPointer(),0,SplitIndex);

        if(len>(SplitIndex+1)){
          auto length=len-(SplitIndex+1);
          auto newCache=H::Pointer<char>::Array(length);
          for(H::usize i=0;i<length;i++){
            newCache[i]=s[i+SplitIndex+1];
          }
          Instance->Cache=newCache;
        }else{
          Instance->Cache.Set_nullptr();
        }

        return r;
      }
    }
    auto data=Instance->Read();
    if(!data){
      return "";
    }
    if(Instance->Cache){
      auto beginIndex=Instance->Cache.Length();
      auto length=Instance->Cache.Length();
      auto newCache=Instance->Cache.Clone(Instance->Cache.Length()+data.Length());
      
      for(H::usize i=0;i<length;i++){
        newCache[beginIndex+i]=data[i];
      }

      Instance->Cache=newCache;
    }else{
      Instance->Cache=data;
    }
  }

}

bool SystemProcessWindows::IsStop(){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return true;
  }

  return Instance->IsStop();
}

void SystemProcessWindows::WaitStop(){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return;
  }

  std::list<H::Pointer<char>> dataList;
  H::usize Length=0;
  for(;;){
    auto data=Instance->Read();
    if(!data){
      break;
    }
    dataList.emplace_back(data);
    Length+=data.Length();
  }

  H::usize index=Instance->Cache.Length();
  auto newCache=Instance->Cache.Clone(index+Length);
  for(auto& Item:dataList){
    for(auto c:Item){
      newCache[index++]=c;
    }
  }
  Instance->Cache=newCache;

  Instance->WaitStop();
}

void SystemProcessWindows::Stop(){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return;
  }

  Instance->Stop();
}

int SystemProcessWindows::GetResult(){
  SystemProcessWindows_Instance* Instance;

  Instance=static_cast<SystemProcessWindows_Instance*>(this->Instance);

  if(Instance==nullptr){
    return -1;
  }

  return Instance->Result;
}




#endif



